/// ===============================================================================
/// Copyright (C) 2011  Ron Cresswell
/// ===============================================================================
/// This program is free software; you can redistribute it and/or
/// modify it under the terms of the GNU General Public License
/// as published by the Free Software Foundation; either version 2
/// of the License, or (at your option) any later version.
/// 
/// This program is distributed in the hope that it will be useful,
/// but WITHOUT ANY WARRANTY; without even the implied warranty of
/// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
/// GNU General Public License for more details.
/// 
/// You should have received a copy of the GNU General Public License
/// along with this program; if not, write to the Free Software
/// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
/// ===============================================================================
/// 
/// Project:        SharePoint Filtered Search
/// Author:         Ron Cresswell (ron.cresswell@angrymansoftware.com.au)
/// Company:        Angry Man Software
/// Date:           18/07/2011 (18 July 2011)  
/// Version:        0.97 (Beta)
///
/// ===============================================================================


using System;
using System.Drawing;
using System.Collections.Generic;
using System.Collections;
using System.Text;
using System.Web;
using System.Web.UI;
using System.Web.UI.WebControls;
using System.Web.UI.WebControls.WebParts;
using System.Security.Permissions;
using Microsoft.SharePoint;
using System.Web.UI.HtmlControls;

namespace AngryManSoftware.WebParts
{
    class AMFilteredSearchEditor : EditorPart
    {
        AMSelectItems libraries;
        AMSelectItems columns;
        AMSelectItems searchFields;
        Hashtable colValues;
        TextBox textBox_Color;
        DropDownList ddl_SelectStyle;
        CheckBox checkBox_ShowLibraries;
        CheckBox checkBox_FilterLibraries;
        CheckBox checkBox_ReverseAlpha;
        CheckBox checkBox_ShowMatchingColumns;
        CheckBox checkBox_ShowSearchColumns;
        CheckBox checkBox_ShowHitsInColumns;
        CheckBox checkBox_SearchBoxAbove;
        CheckBox checkBox_UseListBoxes;
        CheckBox checkBox_ShowDebug;
        CheckBox checkbox_ResultGrid;
        TextBox textBox_MaxValues;
        TextBox textBox_SearchLimit;
        Label label_color;
        Label label_style;
        Label label_showlibs;
        Label label_filterlibs;
        Label label_showHitsInColumns;
        Label label_showSearchColumns;
        Label label_showMatches;
        Label label_searchBoxAbove;
        Label label_reversealpha;
        Label label_uselistboxes;
        Label label_showDebug;
        Label label_maxvals;
        Label label_searchlimit;
        Panel aPanel;
        HtmlHead head;
        Literal l1;
        Literal endGap;
        AMFilteredSearch amfs;
        Color mC;
        AMStyle myStyle;
        ControlCollection ctrls;
        Panel[] panels;
        private bool show_libray_links;
        private bool filter_libray_links;
        private bool reverse_alpha;
        private bool show_matching_columns;
        private bool show_hits_in_columns;
        private bool show_search_columns;
        private bool search_box_above;
        //private bool show_results_in_grid;
        private bool use_listboxes;
        private bool show_debug;
        private string table_color = "#F2F3F4";
        private tableStyles table_styles;
        private int max_vals = 10;
        private int search_rtn_lim = 200;
        //
        //
        /// <summary>
        /// Constructor - good place to set default values
        /// for addtl base properties
        /// </summary>
        public AMFilteredSearchEditor(string webPartID)
        {
            this.Title = "Filtered Search Property Editor"; 
            this.ID = "AMFilteredSearchEditor" + webPartID;
        }

        #region web part methods

        protected override void CreateChildControls()
        {
            if (this.WebPartToEdit is AMFilteredSearch)
            {
                amfs = this.WebPartToEdit as AMFilteredSearch;
            }
            try
            {
                libraries = new AMSelectItems("Libraries");
                columns = new AMSelectItems("Columns");
                searchFields = new AMSelectItems("Search Columns","Select any columns from the default library view(s) whose values should be searched before searching the body text");
                colValues = new Hashtable();
                textBox_Color = new TextBox();
                ddl_SelectStyle = new DropDownList();
                checkBox_ShowLibraries = new CheckBox();
                checkBox_FilterLibraries = new CheckBox();
                checkBox_ShowMatchingColumns = new CheckBox();
                checkBox_ShowSearchColumns = new CheckBox();
                checkBox_SearchBoxAbove = new CheckBox();
                checkBox_ShowHitsInColumns = new CheckBox();
                checkBox_ReverseAlpha = new CheckBox();
                checkBox_UseListBoxes = new CheckBox();
                checkBox_ShowDebug = new CheckBox();
                checkbox_ResultGrid = new CheckBox();
                textBox_MaxValues = new TextBox();
                textBox_SearchLimit = new TextBox();
                //
                // Handle all events here rather than in AMSelect objects            
                //
                libraries.addLib.Click += new ImageClickEventHandler(addLib_Click);
                libraries.remLib.Click += new ImageClickEventHandler(remLib_Click);
                columns.addLib.Click += new ImageClickEventHandler(addCol_Click);
                columns.remLib.Click += new ImageClickEventHandler(remCol_Click);
                searchFields.addLib.Click += new ImageClickEventHandler(addSearchField_Click);
                searchFields.remLib.Click += new ImageClickEventHandler(remField_Click);
                head = this.Page.Header;
                l1 = new Literal();
                bool hasAMStyle = false;
                if (head.HasControls())
                {
                    foreach (Control ctrl in head.Controls)
                    {
                        string cid = ctrl.ID;
                        if (cid == "amStyleBlock")
                        {
                            head.Controls.Remove(ctrl);
                            break;
                        }
                    }
                }
                if (!hasAMStyle)
                {
                    if (this.WebPartToEdit is AMFilteredSearch)
                    {
                        amfs = this.WebPartToEdit as AMFilteredSearch;
                        mC = amfs.parseColor(amfs.ColorTheme);
                        myStyle = new AMStyle(mC);
                        l1.Text = myStyle.getStyles();
                        l1.ID = "amStyleBlock";
                        head.Controls.Add(l1);
                    }
                }
                ctrls = this.Controls;
                libraries.addToControls(ref ctrls, false);
                columns.addToControls(ref ctrls, false);
                searchFields.addToControls(ref ctrls, false);
                /*
                 * Now add a box to contain the various other options, rather than mixing
                 * up those rendered here and those rendered by the default propertygrid
                 * editor.
                 * 
                 * 0.96: Two boxes for options. One for search options, and one for display
                 * options
                 */
                AddSearchOptions();                
                AddDisplayOptions();
            }
            catch (Exception ex)
            {
                amfs.Message = amfs.Message + "<br>CreateChildControls: " + ex.Message;
                if (ex.InnerException != null)
                {
                    amfs.Message = amfs.Message + "<br>Inner Exception: " + ex.InnerException.Message;
                }
            }
        }

        public override bool ApplyChanges()
        {
            EnsureChildControls();
            amfs = this.WebPartToEdit as AMFilteredSearch;
            //if (show_debug && !amfs.ShowDebug) // turning debug on
            //{
            //    amfs.Controls.Clear();
            //}            
            try
            {
                if (amfs != null)
                {
                    Box2Hash(amfs.AMLibsAvail, libraries.ListBoxAvailable);
                    Box2Hash(amfs.AMLibsSel, libraries.ListBoxSelected);
                    Box2Hash(amfs.AMColsAvail, columns.ListBoxAvailable);
                    Box2Hash(amfs.AMColsSel, columns.ListBoxSelected);
                    Box2Hash(amfs.AMSearchColsSel, searchFields.ListBoxSelected);
                    Box2Hash(amfs.AMSearchColsAvail, searchFields.ListBoxAvailable);
                    table_color = textBox_Color.Text;
                    amfs.ColorTheme = table_color;
                    table_styles = (tableStyles)Enum.Parse(typeof(tableStyles), ddl_SelectStyle.SelectedItem.Text);
                    amfs.Table_Style = table_styles;
                    show_libray_links = checkBox_ShowLibraries.Checked;
                    filter_libray_links = checkBox_FilterLibraries.Checked;
                    show_matching_columns = checkBox_ShowMatchingColumns.Checked;
                    show_hits_in_columns = checkBox_ShowHitsInColumns.Checked;
                    show_search_columns = checkBox_ShowSearchColumns.Checked;
                    search_box_above = checkBox_SearchBoxAbove.Checked;
                    reverse_alpha = checkBox_ReverseAlpha.Checked;
                    use_listboxes = checkBox_UseListBoxes.Checked;
                    show_debug = checkBox_ShowDebug.Checked;
                    amfs.ShowLibraryLink = show_libray_links;
                    amfs.FilterLibraryLink = filter_libray_links;
                    amfs.SearchBoxAbove = search_box_above;
                    amfs.ShowHitsInColumns = show_hits_in_columns;
                    amfs.ShowMatchingColumns = show_matching_columns;
                    amfs.ShowSearchColumns = show_search_columns;
                    amfs.ReverseAlpha = reverse_alpha;
                    amfs.UseListBoxes = use_listboxes;
                    amfs.ShowDebug = show_debug;
                    if (!Int32.TryParse(textBox_MaxValues.Text, out max_vals))
                    {
                        max_vals = 10;
                    }
                    amfs.MaxVals = max_vals;
                    if (!Int32.TryParse(textBox_SearchLimit.Text, out search_rtn_lim))
                    {
                        search_rtn_lim = 200;
                    }
                    amfs.SearchReturnLimit = search_rtn_lim;
                    amfs.UpdateColumnValues();
                }
            }
            catch (Exception ex)
            {
                amfs.Message = amfs.Message + "<br>ApplyChanges: " + ex.Message;
                if (ex.InnerException != null)
                {
                    amfs.Message = amfs.Message + "<br>Inner Exception: " + ex.InnerException.Message;
                }
            }
            return true;
        }
        /// <summary>
        /// On entering editor mode, the web part persistent properties are used to set the 
        /// various options such as available libraries, selected columns etc.
        /// If the "Available" list boxes are empty, this routine is also where they are populated
        /// </summary>
        public override void SyncChanges()
        {
            EnsureChildControls();
            amfs = this.WebPartToEdit as AMFilteredSearch;
            try
            {
                if (amfs != null)
                {
                    Hash2Box(amfs.AMLibsAvail, libraries.ListBoxAvailable);
                    Hash2Box(amfs.AMLibsSel, libraries.ListBoxSelected);
                    Hash2Box(amfs.AMColsAvail, columns.ListBoxAvailable);
                    Hash2Box(amfs.AMColsSel, columns.ListBoxSelected);
                    Hash2Box(amfs.AMSearchColsSel, searchFields.ListBoxSelected);
                    Hash2Box(amfs.AMSearchColsAvail, searchFields.ListBoxAvailable);
                    table_color = amfs.ColorTheme;
                    table_styles = amfs.Table_Style;
                    show_libray_links = amfs.ShowLibraryLink;
                    filter_libray_links = amfs.FilterLibraryLink;
                    search_box_above = amfs.SearchBoxAbove;
                    show_hits_in_columns = amfs.ShowHitsInColumns;
                    show_matching_columns = amfs.ShowMatchingColumns;
                    show_search_columns = amfs.ShowSearchColumns;
                    reverse_alpha = amfs.ReverseAlpha;
                    use_listboxes = amfs.UseListBoxes;
                    show_debug = amfs.ShowDebug;
                    max_vals = amfs.MaxVals;
                    search_rtn_lim = amfs.SearchReturnLimit;
                    textBox_Color.Text = table_color;
                    ddl_SelectStyle.Items.Clear();
                    //Get the available style names
                    string[] styles = Enum.GetNames(typeof(tableStyles));
                    //populate the drop down list:
                    int index = -1;
                    for (int i = 0; i < styles.Length; i++)
                    {
                        ListItem item = new ListItem(styles[i], styles[i]);
                        ddl_SelectStyle.Items.Add(item);
                        if (styles[i] == Enum.GetName(typeof(tableStyles), table_styles))
                        {
                            index = i;
                        }
                    }
                    if (index < ddl_SelectStyle.Items.Count && index > -1)
                    {
                        ddl_SelectStyle.SelectedIndex = index;
                    }
                    textBox_MaxValues.Text = max_vals.ToString();
                    textBox_SearchLimit.Text = search_rtn_lim.ToString();
                    checkBox_ShowLibraries.Checked = show_libray_links;
                    checkBox_FilterLibraries.Checked = filter_libray_links;
                    checkBox_ShowMatchingColumns.Checked = show_matching_columns;
                    checkBox_ShowHitsInColumns.Checked = show_hits_in_columns;
                    checkBox_ShowSearchColumns.Checked = show_search_columns;
                    checkBox_SearchBoxAbove.Checked = search_box_above;
                    checkBox_ReverseAlpha.Checked = reverse_alpha;
                    checkBox_UseListBoxes.Checked = use_listboxes;
                    checkBox_ShowDebug.Checked = show_debug;
                }
                //Loop through all lists on site - if they aren't already in either "Available" 
                // or "Selected" then add them to "Available"
                SPWeb thisWeb = SPContext.Current.Web;
                foreach (SPList aList in thisWeb.Lists)
                {
                    if (!aList.Hidden && (aList.BaseType == SPBaseType.DocumentLibrary) && (aList.ItemCount > 0))
                    {
                        SPUser me = SPContext.Current.Web.CurrentUser;
                        if (aList.DoesUserHavePermissions(me, SPBasePermissions.ViewListItems))
                        {
                            ListItem li = new ListItem(aList.Title, aList.ID.ToString());
                            if (!libraries.ListBoxAvailable.Items.Contains(li))
                            {
                                if (!libraries.ListBoxSelected.Items.Contains(li)) // only add it if it's not already in the selected list.
                                {
                                    libraries.ListBoxAvailable.Items.Add(li);
                                }
                            }
                        }
                    }
                }
                /*
                 * Now loop through the libraries in "Selected" and extract the displayed columns
                 * - ensure that they are in "Available" or "Selected" search columns
                 */
                List<string> validFieldList = new List<string>();
                foreach (ListItem li in libraries.ListBoxSelected.Items)
                {
                    string ListID = li.Value;
                    Guid lguid = new Guid(ListID);
                    SPList aList = thisWeb.Lists.GetList(lguid, true);
                    SPView aView = aList.DefaultView;
                    SPViewFieldCollection vFields = aView.ViewFields;
                    foreach (string sField in vFields)
                    {
                        if (!validFieldList.Contains(sField))
                        {
                            validFieldList.Add(sField);
                        }
                        SPField aField = aList.Fields.GetFieldByInternalName(sField);
                        //if (aField.Title == "Type")
                        //{
                        //    SPFieldType huh = aField.Type;
                        //}
                        //Note - the "Name" and "Type" fields are actually a "Computed" type 
                        if ((aField.Type == SPFieldType.Text) ||
                            (aField.Type == SPFieldType.Choice) ||
                            (aField.Type == SPFieldType.Lookup) ||
                            (aField.Type == SPFieldType.MultiChoice) ||
                            (aField.Type == SPFieldType.URL))
                        {
                            ListItem searchItem = new ListItem(aField.Title, aField.InternalName);
                            if (!searchFields.ListBoxAvailable.Items.Contains(searchItem) && !(searchFields.ListBoxSelected.Items.Contains(searchItem)))
                            {
                                searchFields.ListBoxAvailable.Items.Add(searchItem);
                            }
                            //string displayName = aField.Title;
                            //if (!fieldList.Contains(displayName))
                            //{
                            //    fieldList.Add(displayName);
                            //}
                        }
                    }
                    pruneInvalidFields(searchFields.ListBoxAvailable, validFieldList);
                    pruneInvalidFields(searchFields.ListBoxSelected, validFieldList);
                    SortListBox(searchFields.ListBoxAvailable);
                    SortListBox(searchFields.ListBoxSelected);
                }
            }
            catch (Exception ex)
            {
                amfs.Message = amfs.Message + "<br>SyncChanges: " + ex.Message;
                if (ex.InnerException != null)
                {
                    amfs.Message = amfs.Message + "<br>Inner Exception: " + ex.InnerException.Message;
                }
            }
        }

        #endregion

        #region event methods
        /// <summary>
        /// Event that moves a library from "Available" to "Selected"
        /// </summary>
        /// <param name="sender">the object that was clicked</param>
        /// <param name="e">the event arguments</param>
        void addLib_Click(object sender, ImageClickEventArgs e)
        {
            try
            {
                //
                // Broke it again! This time by using nested controls in the html table.
                //  When it was literals, labels and listboxes, all controls were in the top
                //  level. Now I'm gonna have to iterate through to find the right control.
                //
                // Of course, if I bind the listbox to a datasource that is, say, a List<string>
                // I could just move data between lists... That would be the better way to go.
                //
                // Step 1 - move the item
                ListBox lba = new ListBox();
                ListBox lbs = new ListBox();
                for (int i = 0; i < this.Controls.Count; i++)
                {
                    Control ctrl = this.Controls[i];
                    if ((ctrl is ListBox) && (ctrl.ID == "ListBox_Libraries_sel"))
                    {
                        lbs = (ListBox)ctrl;
                    }
                    else if ((ctrl is ListBox) && (ctrl.ID == "ListBox_Libraries_avail"))
                    {
                        lba = (ListBox)ctrl;
                        break;
                    }
                }
                if (lba.Items.Count > 0)
                {
                    if (lba.SelectedItem != null)
                    {
                        ListItem item = lba.SelectedItem;
                        lba.Items.Remove(item);
                        lbs.Items.Add(item);
                        lba.ClearSelection();
                        lbs.ClearSelection();
                    }
                }
                //Step 2 - Add new columns to available columns if not already there.
                FillAvailableColumns(lbs);
            }
            catch (Exception ex)
            {
                amfs.Message = amfs.Message + "<br>addLib_Click: " + ex.Message;
                if (ex.InnerException != null)
                {
                    amfs.Message = amfs.Message + "<br>Inner Exception: " + ex.InnerException.Message;
                }
            }
        }
        /// <summary>
        /// Event that moves a column from "Available" to "Selected"
        /// </summary>
        /// <param name="sender">the object that was clicked</param>
        /// <param name="e">the event arguments</param>
        void addCol_Click(object sender, ImageClickEventArgs e)
        {
            try
            {
                // Step 1 - move the item
                ListBox lba = new ListBox();
                ListBox lbs = new ListBox();
                for (int i = 0; i < this.Controls.Count; i++)
                {
                    Control ctrl = this.Controls[i];
                    if ((ctrl is ListBox) && (ctrl.ID == "ListBox_Columns_sel"))
                    {
                        lbs = (ListBox)ctrl;
                    }
                    else if ((ctrl is ListBox) && (ctrl.ID == "ListBox_Columns_avail"))
                    {
                        lba = (ListBox)ctrl;
                        break;
                    }
                }
                if ((lba != null) && (lbs != null))
                {
                    if (lba.Items.Count > 0)
                    {
                        int[] indices = lba.GetSelectedIndices(); //not used. For future expension (multiple select)
                        if (lba.SelectedItem != null)
                        {
                            ListItem item = lba.SelectedItem;
                            bool columnOk = upDateValues(item);
                            if (columnOk)
                            {
                                lba.Items.Remove(item);
                                //The item value represents its position in the list. Here we strip off its
                                // position in the "Available" list and add its index in the "Selected" list
                                //
                                // NOTE: Must also renumber the listitem values when a column is removed - or
                                // there are gaps in the numbering (coupled with duplicate numbers)
                                string val = item.Value.Substring(0, item.Value.LastIndexOf('_'));
                                item.Value = val + "_" + lbs.Items.Count;
                                lbs.Items.Add(item);
                                //sort? Ok, that worked. However, not really what I was aiming for!
                                // I sorted the column names. I wanted to sort the column value options!!!
                                // Still. Useful to know this bubble sort works :)
                                string dummy;
                                for (int ili = 0; ili < lbs.Items.Count - 1; ili++)
                                {
                                    for (int jli = ili; jli < lbs.Items.Count; jli++)
                                    {
                                        char ic = lbs.Items[ili].Text.ToLower().ToCharArray()[0];
                                        char jc = lbs.Items[jli].Text.ToLower().ToCharArray()[0];
                                        if (ic > jc)
                                        {
                                            dummy = lbs.Items[ili].Text;
                                            lbs.Items[ili].Text = lbs.Items[jli].Text;
                                            lbs.Items[jli].Text = dummy;
                                            dummy = lbs.Items[ili].Value;
                                            lbs.Items[ili].Value = lbs.Items[jli].Value;
                                            lbs.Items[jli].Value = dummy;
                                        }
                                    }
                                }
                                //Now after all that effort at keeping the indices, throw them away and renumber:
                                columnListBoxRenumber(lbs);
                            }
                            lba.ClearSelection();
                            lbs.ClearSelection();
                        }
                    }
                }
                //step 2 - There isn't a step 2. That was only needed for the libraries thing... 
            }
            catch (Exception ex)
            {
                amfs.Message = amfs.Message + "<br>addCol_Click: " + ex.Message;
                if (ex.InnerException != null)
                {
                    amfs.Message = amfs.Message + "<br>Inner Exception: " + ex.InnerException.Message;
                }
            }
        }
        /// <summary>
        /// Event that moves a column to be searched from "Available" to "Selected"
        /// </summary>
        /// <param name="sender">the object that was clicked</param>
        /// <param name="e">the event arguments</param>
        void addSearchField_Click(object sender, ImageClickEventArgs e)
        {
            try
            {
                ListBox lba = new ListBox();
                ListBox lbs = new ListBox();
                for (int i = 0; i < this.Controls.Count; i++)
                {
                    Control ctrl = this.Controls[i];
                    if ((ctrl is ListBox) && (ctrl.ID == "ListBox_Search_Columns_sel"))
                    {
                        lbs = (ListBox)ctrl;
                    }
                    else if ((ctrl is ListBox) && (ctrl.ID == "ListBox_Search_Columns_avail"))
                    {
                        lba = (ListBox)ctrl;
                        break;
                    }
                }
                if ((lba != null) && (lbs != null))
                {
                    if (lba.Items.Count > 0)
                    {
                        int[] indices = lba.GetSelectedIndices();
                        if (lba.SelectedItem != null)
                        {
                            ListItem item = lba.SelectedItem;
                            lba.Items.Remove(item);
                            lbs.Items.Add(item);
                            SortListBox(lbs);
                            lba.ClearSelection();
                            lbs.ClearSelection();
                        }
                    }
                }
            }
            catch (Exception ex)
            {
                amfs.Message = amfs.Message + "<br>addSearchField_Click: " + ex.Message;
                if (ex.InnerException != null)
                {
                    amfs.Message = amfs.Message + "<br>Inner Exception: " + ex.InnerException.Message;
                }
            }
        }
        /// <summary>
        /// Event that moves a library from "Selected" to "Available"
        /// </summary>
        /// <param name="sender">the object that was clicked</param>
        /// <param name="e">the event arguments</param>
        void remLib_Click(object sender, ImageClickEventArgs e)
        {
            try
            {
                //Step 1
                ListBox lba = new ListBox();
                ListBox lbs = new ListBox();
                for (int i = 0; i < this.Controls.Count; i++)
                {
                    Control ctrl = this.Controls[i];
                    if ((ctrl is ListBox) && (ctrl.ID == "ListBox_Libraries_sel"))
                    {
                        lbs = (ListBox)ctrl;
                    }
                    else if ((ctrl is ListBox) && (ctrl.ID == "ListBox_Libraries_avail"))
                    {
                        lba = (ListBox)ctrl;
                        break;
                    }
                }
                if (lbs.Items.Count > 0)
                {
                    if (lbs.SelectedItem != null)
                    {
                        ListItem item = lbs.SelectedItem;
                        lbs.Items.Remove(item);
                        lba.Items.Add(item);
                        lbs.ClearSelection();
                        lba.ClearSelection();
                    }
                }
                //Step 2 - remove column if this was the only library in which it appeared
                ListItemCollection lic = columns.ListBoxSelected.Items;
                columns.ListBoxSelected.Items.Clear();
                columns.ListBoxAvailable.Items.Clear();
                FillAvailableColumns(lbs);
            }
            catch (Exception ex)
            {
                amfs.Message = amfs.Message + "<br>remLib_Click" + ex.Message;
                if (ex.InnerException != null)
                {
                    amfs.Message = amfs.Message + "<br>Inner Exception: " + ex.InnerException.Message;
                }
            }
        }

        /// <summary>
        /// Event that moves a column from "Selected" to "Available"
        /// </summary>
        /// <param name="sender">the object that was clicked</param>
        /// <param name="e">the event arguments</param>
        void remCol_Click(object sender, ImageClickEventArgs e)
        {
            try
            {
                ListBox lba = new ListBox();
                ListBox lbs = new ListBox();
                for (int i = 0; i < this.Controls.Count; i++)
                {
                    Control ctrl = this.Controls[i];
                    if ((ctrl is ListBox) && (ctrl.ID == "ListBox_Columns_sel"))
                    {
                        lbs = (ListBox)ctrl;
                    }
                    else if ((ctrl is ListBox) && (ctrl.ID == "ListBox_Columns_avail"))
                    {
                        lba = (ListBox)ctrl;
                        break;
                    }
                }
                if (lbs.Items.Count > 0)
                {
                    if (lbs.SelectedItem != null)
                    {
                        ListItem item = lbs.SelectedItem;
                        lbs.Items.Remove(item);
                        lba.Items.Add(item);
                        lbs.ClearSelection();
                        lba.ClearSelection();
                        columnListBoxRenumber(lbs);
                    }
                }
            }
            catch (Exception ex)
            {
                amfs.Message = amfs.Message + "<br>remCol_Click: " + ex.Message;
                if (ex.InnerException != null)
                {
                    amfs.Message = amfs.Message + "<br>Inner Exception: " + ex.InnerException.Message;
                }
            }
        }

        private void columnListBoxRenumber(ListBox lbs)
        {
            int nItems = lbs.Items.Count;
            for(int i=0;i<nItems;i++)           
            {
                ListItem item = lbs.Items[i];
                string val = item.Value.Substring(0, item.Value.LastIndexOf('_'));
                item.Value = val + "_" + i.ToString();
            }
        }
        /// <summary>
        /// Event that moves a column to be searched from "Selected" to "Available"
        /// </summary>
        /// <param name="sender">the object that was clicked</param>
        /// <param name="e">the event arguments</param>
        void remField_Click(object sender, ImageClickEventArgs e)
        {
            try
            {
                ListBox lba = new ListBox();
                ListBox lbs = new ListBox();
                for (int i = 0; i < this.Controls.Count; i++)
                {
                    Control ctrl = this.Controls[i];
                    if ((ctrl is ListBox) && (ctrl.ID == "ListBox_Search_Columns_sel"))
                    {
                        lbs = (ListBox)ctrl;
                    }
                    else if ((ctrl is ListBox) && (ctrl.ID == "ListBox_Search_Columns_avail"))
                    {
                        lba = (ListBox)ctrl;
                        break;
                    }
                }
                if (lbs.Items.Count > 0)
                {
                    if (lbs.SelectedItem != null)
                    {
                        ListItem item = lbs.SelectedItem;
                        lbs.Items.Remove(item);
                        lba.Items.Add(item);
                        lbs.ClearSelection();
                        lba.ClearSelection();
                    }
                }
            }
            catch (Exception ex)
            {
                amfs.Message = amfs.Message + "<br>remField_Click: " + ex.Message;
                if (ex.InnerException != null)
                {
                    amfs.Message = amfs.Message + "<br>Inner Exception: " + ex.InnerException.Message;
                }
            }
        }

        #endregion

        #region helper methods

        private void AddSearchOptions()
        {
            if (this.WebPartToEdit is AMFilteredSearch)
            {
                amfs = this.WebPartToEdit as AMFilteredSearch;
            }
            try
            {
                aPanel = new Panel();
                aPanel.GroupingText = "Search Options";
                aPanel.BorderStyle = BorderStyle.None;
                aPanel.BorderWidth = new Unit(1);
                label_showlibs = new Label();
                label_filterlibs = new Label();
                label_searchBoxAbove = new Label();
                label_showHitsInColumns = new Label();
                label_showSearchColumns = new Label();
                label_showMatches = new Label();
                label_searchlimit = new Label();
                label_showlibs.Text = "Show link to parent library<br>";
                label_filterlibs.Text = "Filter library link by matching column values<br>";
                label_showMatches.Text = "Display matched column filter values<br>";
                label_showHitsInColumns.Text = "Display hits in Search Columns<br>";
                label_showSearchColumns.Text = "Display values for search columns, whether they contain hits or not<br>";
                label_searchBoxAbove.Text = "Show search box above column choices<br>";
                label_searchlimit.Text = "<br>Limit on search items to return";
                int nPanels = 7;
                panels = new Panel[nPanels];
                for (int i = 0; i < nPanels; i++)
                {
                    panels[i] = new Panel();
                    panels[i].BorderStyle = BorderStyle.None;
                    panels[i].BorderWidth = new Unit(1);
                    switch (i)
                    {
                        case 0:
                            panels[i].Controls.Add(checkBox_ShowLibraries);
                            panels[i].Controls.Add(label_showlibs);
                            break;
                        case 1:
                            panels[i].Controls.Add(checkBox_FilterLibraries);
                            panels[i].Controls.Add(label_filterlibs);
                            break;
                        case 2:
                            panels[i].Controls.Add(checkBox_ShowMatchingColumns);
                            panels[i].Controls.Add(label_showMatches);
                            break;
                        case 3:
                            panels[i].Controls.Add(checkBox_ShowHitsInColumns);
                            panels[i].Controls.Add(label_showHitsInColumns);
                            break;
                        case 4:
                            panels[i].Controls.Add(checkBox_ShowSearchColumns);
                            panels[i].Controls.Add(label_showSearchColumns);
                            break;
                        case 5:
                            panels[i].Controls.Add(checkBox_SearchBoxAbove);
                            panels[i].Controls.Add(label_searchBoxAbove);
                            break;
                        default:
                            panels[i].Controls.Add(textBox_SearchLimit);
                            panels[i].Controls.Add(label_searchlimit);
                            break;
                    }
                    aPanel.Controls.Add(panels[i]);
                    endGap = new Literal();
                    endGap.Text = "<br>";
                    aPanel.Controls.Add(endGap);
                }
                this.Controls.Add(aPanel);
            }
            catch (Exception ex)
            {
                amfs.Message = amfs.Message + "<br>AddSearchOptions: " + ex.Message;
                if (ex.InnerException != null)
                {
                    amfs.Message = amfs.Message + "<br>Inner Exception: " + ex.InnerException.Message;
                }
            }
        }

        private void AddDisplayOptions()
        {
            try
            {
                aPanel = new Panel();
                aPanel.GroupingText = "Web Part Display Options";
                aPanel.BorderStyle = BorderStyle.None;
                aPanel.BorderWidth = new Unit(1);
                label_color = new Label();
                label_style = new Label();
                label_reversealpha = new Label();
                label_uselistboxes = new Label();
                label_showDebug = new Label();
                label_maxvals = new Label();
                label_color.Text = "<br>Table Color (use known color <br>string or #FFFFFF format)<br>";
                label_style.Text = "<br>Table Grid Style<br> ";
                label_reversealpha.Text = "Reverse Column Value Sort Order<br>";
                label_uselistboxes.Text = "Use ListBoxes instead of Checkboxes<br>";
                label_showDebug.Text = "Show TextBox for Diagnostic messages<br>";
                label_maxvals.Text = "Maximum number of unique<br>values for each column<br>";
                int nPanels = 6;
                panels = new Panel[nPanels];
                for (int i = 0; i < nPanels; i++)
                {
                    panels[i] = new Panel();
                    panels[i].BorderStyle = BorderStyle.None;
                    panels[i].BorderWidth = new Unit(1);
                    switch (i)
                    {
                        case 0:
                            panels[i].Controls.Add(label_style);
                            panels[i].Controls.Add(ddl_SelectStyle);
                            break;
                        case 1:
                            panels[i].Controls.Add(label_color);
                            panels[i].Controls.Add(textBox_Color);
                            break;
                        case 2:
                            panels[i].Controls.Add(checkBox_UseListBoxes);
                            panels[i].Controls.Add(label_uselistboxes);
                            break;
                        case 3:
                            panels[i].Controls.Add(checkBox_ReverseAlpha);
                            panels[i].Controls.Add(label_reversealpha);
                            break;
                        case 4:
                            panels[i].Controls.Add(label_maxvals);
                            panels[i].Controls.Add(textBox_MaxValues);
                            break;
                        default:
                            panels[i].Controls.Add(label_showDebug);
                            panels[i].Controls.Add(checkBox_ShowDebug);
                            break;
                    }
                    aPanel.Controls.Add(panels[i]);
                    endGap = new Literal();
                    endGap.Text = "<br>";
                    aPanel.Controls.Add(endGap);
                }
                this.Controls.Add(aPanel);
            }
            catch (Exception ex)
            {
                amfs.Message = amfs.Message + "<br>AddDisplayOptions: " + ex.Message;
                if (ex.InnerException != null)
                {
                    amfs.Message = amfs.Message + "<br>Inner Exception: " + ex.InnerException.Message;
                }
            }
        }

        /// <summary>
        /// This is the routine that examines the document libraries and sets up the
        /// available columns list to be selected from. The selected libraries listbox
        /// is expected to contain item.Text="Library Display Name" & item.Value=GUID of library
        /// Available columns are set with item.Text="Column Display Name" and
        /// item.Value="Column Display Name" + "_" + iType where iType is an integer representing
        /// the type of column (text, choice, lookup etc)
        /// </summary>
        /// <param name="lbs">Listbox containing selected libraries</param>
        private void FillAvailableColumns(ListBox lbs)
        {
            try
            {
                foreach (ListItem item in lbs.Items)
                {
                    string lib_guid = item.Value;
                    Guid libguid = new Guid(lib_guid); // Dangerous. It is possible to pass a listbox which doesn't 
                                                       // contain item values in guid format
                    SPWeb thisWeb = SPContext.Current.Web;
                    SPList aList = thisWeb.Lists.GetList(libguid, false);
                    SPFieldCollection fields = aList.Fields;
                    int i = 0;
                    foreach (SPField field in fields)
                    {
                        if (field.CanBeDeleted)
                        {
                            //if it can be deleted it can't be an integral part of the library definition
                            // - Hence it's either added by the user/owner or part of a custom content type
                            // Either way, it's a good candidate for filtering

                            ListItem li = new ListItem();
                            //field types to consider are:
                            //  single line of text
                            //  choice
                            //  lookup
                            //  person
                            //  time/date
                            //
                            // Note: The listbox selection is done based on the "Value", not the "Text" property
                            // of the list item. Hence each "Value" must be unique to that item or the wrong
                            // selection will be returned. This is why we aren't simply putting the fieldType
                            // in the value field. 
                            //

                            if ((field.Type == SPFieldType.Text) || (field.Type == SPFieldType.Choice) || (field.Type == SPFieldType.User) || (field.Type == SPFieldType.DateTime) || (field.Type == SPFieldType.Lookup))
                            {
                                li.Text = field.Title;
                                li.Value = field.Title + "_" + i.ToString();
                                //
                                // So the list item values in "Available Columns" contain a number appended after 
                                // an underscore which represents the order in which they were added originally.
                                //
                                if (columns.ListBoxAvailable.Items.FindByText(li.Text) == null)
                                {
                                    if ((!columns.ListBoxAvailable.Items.Contains(li)) && (!columns.ListBoxSelected.Items.Contains(li)))
                                    {
                                        columns.ListBoxAvailable.Items.Add(li);
                                        i++;
                                    }
                                }
                            }
                        }
                    }
                }
            }
            catch (Exception ex)
            {
                amfs.Message = amfs.Message + "<br>FillAvailableColumns: " + ex.Message;
                if (ex.InnerException != null)
                {
                    amfs.Message = amfs.Message + "<br>Inner Exception: " + ex.InnerException.Message;
                }
            }
        }

        private static void SortListBox(ListBox lbs)
        {
            string dummy;
            for (int ili = 0; ili < lbs.Items.Count - 1; ili++)
            {
                for (int jli = ili + 1; jli < lbs.Items.Count; jli++)
                {
                    int iCompare = String.Compare(lbs.Items[ili].Text, lbs.Items[jli].Text, StringComparison.CurrentCultureIgnoreCase);
                    if (iCompare > 0)
                    {
                        dummy = lbs.Items[ili].Text;
                        lbs.Items[ili].Text = lbs.Items[jli].Text;
                        lbs.Items[jli].Text = dummy;
                        dummy = lbs.Items[ili].Value;
                        lbs.Items[ili].Value = lbs.Items[jli].Value;
                        lbs.Items[jli].Value = dummy;
                    }
                }
            }
        }

        /// <summary>
        /// When a column is added, loop through to count the number of
        /// unique values. If this exceeds the maximum, don't add it,
        /// but display an error message instead.
        /// </summary>
        /// <param name="item">List Item from the "Selected Columns" listbox</param>
        private bool upDateValues(ListItem item)
        {
            try
            {
                /*
                 * TODO: 
                 * 1. Sort column values alphabetically 
                 * 2. Display Error message when count exceeded
                 * 3. [Future] When max_vals exceeded, replace checkbox list with multi-select listbox
                 */
                string name = item.Text;
                string val = item.Value;
                max_vals = amfs.MaxVals;
                bool column_Ok = true;
                SPWeb thisWeb = SPContext.Current.Web;
                List<string> column_values = new List<string>();
                foreach (ListItem lib in libraries.ListBoxSelected.Items)
                {
                    string lib_guid = lib.Value;
                    Guid libguid = new Guid(lib_guid);

                    SPList aList = thisWeb.Lists.GetList(libguid, false);
                    if (aList.Fields.ContainsField(name))
                    {
                        foreach (SPListItem spListItem in aList.Items)
                        {
                            if (spListItem[name] != null)
                            {
                                object AMystery = spListItem[name];
                                string Col_val = spListItem[name].ToString();
                                if (!column_values.Contains(Col_val))
                                {
                                    column_values.Add(Col_val);
                                }
                            }
                            if (column_values.Count > max_vals)
                            {
                                column_Ok = false;
                                break;
                            }
                        }
                    }
                    if (!column_Ok)
                    {
                        break;
                    }
                }
                return column_Ok;
            }
            catch (Exception ex)
            {
                amfs.Message = amfs.Message + "<br>upDateValues: " + ex.Message;
                if (ex.InnerException != null)
                {
                    amfs.Message = amfs.Message + "<br>Inner Exception: " + ex.InnerException.Message;
                }
                return false;
            }
        }

        private void pruneInvalidFields(ListBox listBox, List<string> validFieldList)
        {
            try
            {
                List<ListItem> invalidItems = new List<ListItem>();
                foreach (ListItem li in listBox.Items)
                {
                    if (!validFieldList.Contains(li.Text))
                    {
                        invalidItems.Add(li);
                    }
                }
                foreach (ListItem invalidItem in invalidItems)
                {
                    listBox.Items.Remove(invalidItem);
                }
            }
            catch (Exception ex)
            {
                amfs.Message = amfs.Message + "<br>PruneInvalidFields: " + ex.Message;
                if (ex.InnerException != null)
                {
                    amfs.Message = amfs.Message + "<br>Inner Exception: " + ex.InnerException.Message;
                }
            }
        }

        private void Hash2Box(Hashtable ht, ListBox lb)
        {
            try
            {
                lb.Items.Clear();
                foreach (string key in ht.Keys)
                {
                    string val = (string)ht[key];
                    ListItem li = new ListItem(key, val);
                    lb.Items.Add(li);
                }
                lb.ClearSelection();
            }
            catch (Exception ex)
            {
                amfs.Message = amfs.Message + "<br>Hash2Box: " + ex.Message;
                if (ex.InnerException != null)
                {
                    amfs.Message = amfs.Message + "<br>Inner Exception: " + ex.InnerException.Message;
                }
            }
        }

        private void Box2Hash(Hashtable ht, ListBox lb)
        {            
            try
            {
                ht.Clear();
                foreach (ListItem item in lb.Items)
                {
                    string key = item.Text;
                    string val = item.Value;
                    ht[key] = val;
                }
            }
            catch (Exception ex)
            {
                amfs.Message = amfs.Message + "<br>Box2Hash: " + ex.Message;
                if (ex.InnerException != null)
                {
                    amfs.Message = amfs.Message + "<br>Inner Exception: " + ex.InnerException.Message;
                }
            }
        }

        #endregion
    }

    /// <summary>
    /// A class encapsulating two listboxes and add/remove buttons
    /// </summary>
    class AMSelectItems
    {
        private ListBox lba;
        private ListBox lbs;
        public ImageButton addLib;
        public ImageButton remLib;
        public ListBox ListBoxAvailable
        {
            get { return lba; }
            set { lba = value; }
        }
        public ListBox ListBoxSelected
        {
            get { return lbs; }
            set { lbs = value; }
        }
        private string subject;
        public string Subject
        {
            get { return subject; }
            set { subject = value; }
        }
        private string info_message;
        public string InfoMessage
        {
            get { return info_message; }
            set { info_message = value; }
        }
        private object depends;
        public object DependsOnMe
        {
            get { return depends; }
            set { depends = value; }
        }
        /// <summary>
        /// A list of items split into "available" and "selected"
        /// </summary>
        /// <param name="s">The subject</param>
        public AMSelectItems(string sin)
        {
            string s = sin.Replace(' ', '_');
            lba = new ListBox();
            lbs = new ListBox();
            lbs.ID = "ListBox_" + s + "_sel";
            lba.ID = "ListBox_" + s + "_avail";            
            addLib = new ImageButton();
            remLib = new ImageButton();
            subject = sin;
            Unit width = new Unit(100.0, UnitType.Percentage);
            lba.Items.Clear();
            lbs.Items.Clear();
            lba.Width = width;
            lbs.Width = width;
            InfoMessage = "";
        }
        public AMSelectItems(string sin, string _message)
        {
            string s = sin.Replace(' ', '_');
            lba = new ListBox();
            lbs = new ListBox();
            lbs.ID = "ListBox_" + s + "_sel";
            lba.ID = "ListBox_" + s + "_avail";
            addLib = new ImageButton();
            remLib = new ImageButton();
            subject = sin;
            Unit width = new Unit(100.0, UnitType.Percentage);
            lba.Items.Clear();
            lbs.Items.Clear();
            lba.Width = width;
            lbs.Width = width;
            InfoMessage = _message;
        }

        void lba_SelectedIndexChanged(object sender, EventArgs e)
        {
            if (sender is ListBox)
            {
                ListBox b = sender as ListBox;
                int index = b.SelectedIndex;
            }
        }

        //methods
        internal void addToControls(ref ControlCollection controls, bool useTables)
        {
            if (useTables)
            {
                /* set up a table with 5 rows. Top & bottom row contain listboxes,
                 * 
                 * 
                 *  -------------------------------
                 * |                               | <- "Selected"
                 *  -------------------------------
                 * |                               |
                 * |                               |
                 * |                               | <- ListBox (lbs)
                 * |                               |
                 * |                               |
                 *  -------------------------------
                 * |          |_________|          | <- "Add" button, "Add" label
                 * |          |         |          | <- "Remove" button, "Remove" label
                 *  -------------------------------
                 * |                               | <- "Available"
                 *  -------------------------------
                 * |                               |
                 * |                               |
                 * |                               | <- ListBox (lba)
                 * |                               |
                 * |                               |
                 *  -------------------------------
                 * 
                 */
                addLib.ImageUrl = "/_layouts/images/amAdd.gif";
                remLib.ImageUrl = "/_layouts/images/amRem.gif";
                //
                // Labels and literals:
                //
                Literal fieldSetOpen = new Literal();
                fieldSetOpen.Text = "<fieldset><legend> " + subject + " </legend>";
                Literal fieldSetClose = new Literal();
                fieldSetClose.Text = "</fieldset>";
                Label addLabel = new Label();
                Label remLabel = new Label();
                addLabel.ForeColor = Color.Green;
                remLabel.ForeColor = Color.Red;
                Label AvailableLabel = new Label();
                Label SelectedLabel = new Label();
                AvailableLabel.ForeColor = Color.Blue;
                SelectedLabel.ForeColor = Color.Blue;
                addLabel.Text = "Add";
                remLabel.Text = "Remove";
                //
                // Create tables and table elements
                //
                HtmlTable SelectTable = new HtmlTable(); // 5 rows, middle row has 3 cols (others span)
                SelectTable.ID = "SelectTable_" + subject;
                SelectTable.Width = "100%";
                SelectTable.Style.Add("text-align", "center");
                SelectTable.Border = 0;
                for (int irow = 0; irow < 5; irow++)
                {
                    HtmlTableCell td;
                    SelectTable.Rows.Add(new HtmlTableRow());
                    switch (irow)
                    {
                        case 2:
                            for (int icol = 0; icol < 3; icol++)
                            {
                                td = new HtmlTableCell();
                                SelectTable.Rows[irow].Cells.Add(td);
                            }
                            break;
                        default:
                            td = new HtmlTableCell();
                            td.ColSpan = 3;
                            td.Align = "center";
                            SelectTable.Rows[irow].Cells.Add(td);
                            break;
                    }
                }

                HtmlTable innerTable = new HtmlTable();
                innerTable.Rows.Add(new HtmlTableRow());
                innerTable.Rows.Add(new HtmlTableRow());
                innerTable.Rows[0].Cells.Add(new HtmlTableCell());
                innerTable.Rows[1].Cells.Add(new HtmlTableCell());
                //
                // Set cell properties
                //
                innerTable.Rows[0].VAlign = "top";
                innerTable.Rows[1].VAlign = "bottom";
                innerTable.Rows[0].Cells[0].Style.Add("text-align", "left");
                innerTable.Rows[1].Cells[0].Style.Add("text-align", "right");
                //
                // fill the table
                //
                innerTable.Rows[0].Cells[0].Controls.Add(addLabel);
                innerTable.Rows[1].Cells[0].Controls.Add(remLabel);

                SelectTable.Rows[0].Cells[0].Controls.Add(SelectedLabel);
                SelectTable.Rows[1].Cells[0].Controls.Add(lbs);
                SelectTable.Rows[2].Cells[0].Controls.Add(addLib);
                SelectTable.Rows[2].Cells[1].Controls.Add(innerTable);
                SelectTable.Rows[2].Cells[2].Controls.Add(remLib);
                SelectTable.Rows[3].Cells[0].Controls.Add(AvailableLabel);
                SelectTable.Rows[4].Cells[0].Controls.Add(lba);
                //
                // Add it in...surrounded by a fieldset box
                //
                controls.Add(fieldSetOpen);
                controls.Add(SelectTable);
                controls.Add(fieldSetClose);
            }
            else // this is the "old" code. However, is does not use nested controls - so currently we're using it.
            {
                addLib.ImageUrl = "/_layouts/images/amAdd.gif";
                remLib.ImageUrl = "/_layouts/images/amRem.gif";
                Literal literal1 = new Literal();
                Literal literal2 = new Literal();
                Literal literal3 = new Literal();
                Literal literal4 = new Literal();
                Literal literal5 = new Literal();
                /* set up a table with 3 rows. Top & bottom row contain listboxes,
                 * 
                 * 
                 *  -------------------------------
                 * |                               |
                 * |                               |
                 * |                               |
                 * |                               |
                 * |                               |
                 *  -------------------------------
                 * |          |_________|          |
                 * |          |         |          |
                 *  -------------------------------
                 * |                               |
                 * |                               |
                 * |                               |
                 * |                               |
                 * |                               |
                 * |                               |
                 *  -------------------------------
                 * 
                 * middle row contains add/remove buttons
                 * layout will be:
                 * literal1
                 * listbox "Libs Available"
                 * literal2
                 * buton addLib
                 * literal3
                 * button remLib
                 * literal4
                 * listbox "Libs selected"
                 * literal5
                 */
                literal1.Text = "<fieldset><legend>" + subject + "</legend>"
                    + "<table style=\"width:100%;\" border=\"0\" >"
                    + "<tr><td colspan=\"3\" style=\"width:100%; color: #009900; text-align: center\">"
                    + InfoMessage + "<br></td></tr>"
                    + "<tr>"
                    + "<td colspan=\"3\" style=\"width:100%; color: #0000FF; text-align: center\">"
                    + "Selected " + subject
                    + "</td>"
                    + "</tr>"
                    + "<tr>"
                    + "<td colspan=\"3\" style=\"width:100%;\">"; // + libs_selected +
                literal2.Text = "</td>"
                    + "</tr>"
                    + "<tr>"
                    + "<td rowspan=\"2\" style=\"text-align: center\">"; // + addLib button +
                literal3.Text = "</td>"
                    + "<td  style=\"color: #00CC00; text-align: left\">"
                    + "Add"
                    + "</td>"
                    + "<td rowspan=\"2\" style=\"text-align: center\">"; // + remLib +
                literal4.Text = "</td>"
                    + "</tr>"
                    + "<tr>"
                    + "<td style=\"color: #FF0000; text-align: right\">"
                    + "Remove"
                    + "</td>"
                    + "</tr>"
                    + "<tr>"
                    + "<td colspan=\"3\" style=\"width:100%; color: #0000FF; text-align: center\">"
                    + "Available " + subject
                    + "</td>"
                    + "</tr>"
                    + "<tr>"
                    + "<td colspan=\"3\" style=\"text-align: center\">"; // + libs_available +
                literal5.Text = "</td>"
                    + "</tr>"
                    + "</table></fieldset>";
                controls.Add(literal1);
                controls.Add(lbs);
                controls.Add(literal2);
                controls.Add(addLib);
                controls.Add(literal3);
                controls.Add(remLib);
                controls.Add(literal4);
                controls.Add(lba);
                controls.Add(literal5);
            }
        }
        internal void updateMyValues()
        {
        }
        internal void remLib_Click(object sender, ImageClickEventArgs e)
        {
            if (lbs.Items.Count > 0)
            {
                if (lbs.SelectedItem != null)
                {
                    ListItem item = lbs.SelectedItem;
                    lbs.Items.Remove(item);
                    lba.Items.Add(item);
                }
            }
        }

        internal void addLib_Click(object sender, ImageClickEventArgs e)
        {
            if (lba.Items.Count > 0)
            {
                if (lba.SelectedItem != null)
                {
                    ListItem item = lba.SelectedItem;
                    lba.Items.Remove(item);
                    lbs.Items.Add(item);
                }
            }
        }
    }
}
